home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / shells / tcshsrc.zoo / tcsh / sh.exec.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-01  |  19.1 KB  |  817 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/sh.exec.c,v 3.1 1991/07/15 19:37:24 christos Exp $ */
  2. /*
  3.  * sh.exec.c: Search, find, and execute a command!
  4.  */
  5. /*-
  6.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "config.h"
  38. RCSID("$Id: sh.exec.c,v 3.1 1991/07/15 19:37:24 christos Exp $")
  39.  
  40. #include "sh.h"
  41. #include "tc.h"
  42. #include "tw.h"
  43.  
  44. /*
  45.  * C shell
  46.  */
  47.  
  48. #ifdef __MINT__
  49. extern char **environ;
  50. int csh_execve(char *, char **, char **);
  51. #define execv(f, t) csh_execve(f, t, environ)
  52. #endif
  53.  
  54. /*
  55.  * System level search and execute of a command.
  56.  * We look in each directory for the specified command name.
  57.  * If the name contains a '/' then we execute only the full path name.
  58.  * If there is no search path then we execute only full path names.
  59.  */
  60.  
  61. /*
  62.  * As we search for the command we note the first non-trivial error
  63.  * message for presentation to the user.  This allows us often
  64.  * to show that a file has the wrong mode/no access when the file
  65.  * is not in the last component of the search path, so we must
  66.  * go on after first detecting the error.
  67.  */
  68. static char *exerr;        /* Execution error message */
  69. static Char *expath;        /* Path for exerr */
  70.  
  71. /*
  72.  * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
  73.  * to hash execs.  If it is allocated (havhash true), then to tell
  74.  * whether ``name'' is (possibly) present in the i'th component
  75.  * of the variable path, you look at the bit in xhash indexed by
  76.  * hash(hashname("name"), i).  This is setup automatically
  77.  * after .login is executed, and recomputed whenever ``path'' is
  78.  * changed.
  79.  * The two part hash function is designed to let texec() call the
  80.  * more expensive hashname() only once and the simple hash() several
  81.  * times (once for each path component checked).
  82.  * Byte size is assumed to be 8.
  83.  */
  84. #define    HSHSIZ        8192    /* 1k bytes */
  85. #define HSHMASK        (HSHSIZ - 1)
  86. #define HSHMUL        243
  87. static char xhash[HSHSIZ / 8];
  88.  
  89. #define hash(a, b)    ((a) * HSHMUL + (b) & HSHMASK)
  90. #define bit(h, b)    ((h)[(b) >> 3] & 1 << ((b) & 7))    /* bit test */
  91. #define bis(h, b)    ((h)[(b) >> 3] |= 1 << ((b) & 7))    /* bit set */
  92. #ifdef VFORK
  93. static int hits, misses;
  94.  
  95. #endif
  96.  
  97. /* Dummy search path for just absolute search when no path */
  98. static Char *justabs[] = {STRNULL, 0};
  99.  
  100. static    void    pexerr        __P((void));
  101. static    void    texec        __P((Char *, Char **));
  102. static    int    hashname    __P((Char *));
  103.  
  104. void
  105. doexec(t)
  106.     register struct command *t;
  107. {
  108.     register Char *dp, **pv, **av, *sav;
  109.     register struct varent *v;
  110.     register bool slash;
  111.     register int hashval = 0, hashval1, i;
  112.     Char   *blk[2];
  113.  
  114.     /*
  115.      * Glob the command name. We will search $path even if this does something,
  116.      * as in sh but not in csh.  One special case: if there is no PATH, then we
  117.      * execute only commands which start with '/'.
  118.      */
  119.     blk[0] = t->t_dcom[0];
  120.     blk[1] = 0;
  121.     gflag = 0, tglob(blk);
  122.     if (gflag) {
  123.     pv = globall(blk);
  124.     if (pv == 0) {
  125.         setname(short2str(blk[0]));
  126.         stderror(ERR_NAME | ERR_NOMATCH);
  127.     }
  128.     gargv = 0;
  129.     }
  130.     else
  131.     pv = saveblk(blk);
  132.  
  133.     trim(pv);
  134.  
  135.     exerr = 0;
  136.     expath = Strsave(pv[0]);
  137. #ifdef VFORK
  138.     Vexpath = expath;
  139. #endif
  140.  
  141.     v = adrof(STRpath);
  142.     if (v == 0 && expath[0] != '/') {
  143.     blkfree(pv);
  144.     pexerr();
  145.     }
  146.     slash = any(short2str(expath), '/');
  147.  
  148.     /*
  149.      * Glob the argument list, if necessary. Otherwise trim off the quote bits.
  150.      */
  151.     gflag = 0;
  152.     av = &t->t_dcom[1];
  153.     tglob(av);
  154.     if (gflag) {
  155.     av = globall(av);
  156.     if (av == 0) {
  157.         blkfree(pv);
  158.         setname(short2str(expath));
  159.         stderror(ERR_NAME | ERR_NOMATCH);
  160.     }
  161.     gargv = 0;
  162.     }
  163.     else
  164.     av = saveblk(av);
  165.  
  166.     blkfree(t->t_dcom);
  167.     t->t_dcom = blkspl(pv, av);
  168.     xfree((ptr_t) pv);
  169.     xfree((ptr_t) av);
  170.     av = t->t_dcom;
  171.     trim(av);
  172.  
  173.     if (*av == NULL || **av == '\0')
  174.     pexerr();
  175.  
  176.     xechoit(av);        /* Echo command if -x */
  177. #ifdef FIOCLEX
  178.     /*
  179.      * Since all internal file descriptors are set to close on exec, we don't
  180.      * need to close them explicitly here.  Just reorient ourselves for error
  181.      * messages.
  182.      */
  183.     SHIN = 0;
  184.     SHOUT = 1;
  185.     SHDIAG = 2;
  186.     OLDSTD = 0;
  187.     isoutatty = isatty(SHOUT);
  188.     isdiagatty = isatty(SHDIAG);
  189. #else
  190.     closech();            /* Close random fd's */
  191. #endif
  192.     /*
  193.      * We must do this AFTER any possible forking (like `foo` in glob) so that
  194.      * this shell can still do subprocesses.
  195.      */
  196. #ifdef BSDSIGS
  197.     (void) sigsetmask((sigmask_t) 0);
  198. #else                /* BSDSIGS */
  199.     (void) sigrelse(SIGINT);
  200.     (void) sigrelse(SIGCHLD);
  201. #endif                /* BSDSIGS */
  202.  
  203.     /*
  204.      * If no path, no words in path, or a / in the filename then restrict the
  205.      * command search.
  206.      */
  207.     if (v == 0 || v->vec[0] == 0 || slash)
  208.     pv = justabs;
  209.     else
  210.     pv = v->vec;
  211.     sav = Strspl(STRslash, *av);/* / command name for postpending */
  212. #ifdef VFORK
  213.     Vsav = sav;
  214. #endif
  215.     if (havhash)
  216.     hashval = hashname(*av);
  217.     i = 0;
  218. #ifdef VFORK
  219.     hits++;
  220. #endif
  221.     do {
  222.     /*
  223.      * Try to save time by looking at the hash table for where this command
  224.      * could be.  If we are doing delayed hashing, then we put the names in
  225.      * one at a time, as the user enters them.  This is kinda like Korn
  226.      * Shell's "tracked aliases".
  227.      */
  228.     if (!slash && pv[0][0] == '/' && havhash) {
  229.         hashval1 = hash(hashval, i);
  230.         if (!bit(xhash, hashval1))
  231.         goto cont;
  232.     }
  233.     if (pv[0][0] == 0 || eq(pv[0], STRdot))    /* don't make ./xxx */
  234.         texec(*av, av);
  235.     else {
  236.         dp = Strspl(*pv, sav);
  237. #ifdef VFORK
  238.         Vdp = dp;
  239. #endif
  240.         texec(dp, av);
  241. #ifdef VFORK
  242.         Vdp = 0;
  243. #endif
  244.         xfree((ptr_t) dp);
  245.     }
  246. #ifdef VFORK
  247.     misses++;
  248. #endif
  249. cont:
  250.     pv++;
  251.     i++;
  252.     } while (*pv);
  253. #ifdef VFORK
  254.     hits--;
  255. #endif
  256. #ifdef VFORK
  257.     Vsav = 0;
  258. #endif
  259.     xfree((ptr_t) sav);
  260.     pexerr();
  261. }
  262.  
  263. static void
  264. pexerr()
  265. {
  266.     /* Couldn't find the damn thing */
  267.     if (expath) {
  268.     setname(short2str(expath));
  269. #ifdef VFORK
  270.     Vexpath = 0;
  271. #endif
  272.     xfree((ptr_t) expath);
  273.     expath = 0;
  274.     }
  275.     else
  276.     setname("");
  277.     if (exerr)
  278.     stderror(ERR_NAME | ERR_STRING, exerr);
  279.     stderror(ERR_NAME | ERR_COMMAND);
  280. }
  281.  
  282. /*
  283.  * Execute command f, arg list t.
  284.  * Record error message if not found.
  285.  * Also do shell scripts here.
  286.  */
  287. static void
  288. texec(sf, st)
  289.     Char   *sf;
  290.     register Char **st;
  291. {
  292.     register char **t;
  293.     register char *f;
  294.     register struct varent *v;
  295.     register Char **vp;
  296.     Char   *lastsh[2];
  297.     int     fd;
  298.     unsigned char c;
  299.     Char   *st0, **ost;
  300.  
  301.     /* The order for the conversions is significant */
  302.     t = short2blk(st);
  303.     f = short2str(sf);
  304. #ifdef VFORK
  305.     Vt = t;
  306. #endif
  307.     errno = 0;            /* don't use a previous error */
  308. #ifdef apollo
  309.     /*
  310.      * If we try to execute an nfs mounted directory on the apollo, we
  311.      * hang forever. So until apollo fixes that..
  312.      */
  313.     {
  314.     struct stat stb;
  315.     if (stat(f, &stb) == 0 && S_ISDIR(stb.st_mode))
  316.         errno = EISDIR;
  317.     }
  318.     if (errno == 0)
  319. #endif
  320.     (void) execv(f, t);
  321. #ifdef VFORK
  322.     Vt = 0;
  323. #endif
  324.     blkfree((Char **) t);
  325.     switch (errno) {
  326.  
  327.     case ENOEXEC:
  328.     /*
  329.      * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute
  330.      * it, don't feed it to the shell if it looks like a binary!
  331.      */
  332.     if ((fd = open(f, O_RDONLY)) != -1) {
  333.         if (read(fd, (char *) &c, 1) == 1) {
  334.         if (!Isprint(c) && (c != '\n' && c != '\t')) {
  335.             (void) close(fd);
  336.             /*
  337.              * We *know* what ENOEXEC means.
  338.              */
  339.             stderror(ERR_ARCH, f, strerror(errno));
  340.         }
  341.         }
  342. #ifdef _PATH_BSHELL
  343.         else
  344.         c = '#';
  345. #endif
  346.         (void) close(fd);
  347.     }
  348.     /*
  349.      * If there is an alias for shell, then put the words of the alias in
  350.      * front of the argument list replacing the command name. Note no
  351.      * interpretation of the words at this point.
  352.      */
  353.     v = adrof1(STRshell, &aliases);
  354.     if (v == 0) {
  355.         vp = lastsh;
  356.         vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH;
  357.         vp[1] = NOSTR;
  358. #ifdef _PATH_BSHELL
  359.         if (fd != -1 && c != '#')
  360.         vp[0] = STR_BSHELL;
  361. #endif
  362.     }
  363.     else
  364.         vp = v->vec;
  365.     st0 = st[0];
  366.     st[0] = sf;
  367.     ost = st;
  368.     st = blkspl(vp, st);    /* Splice up the new arglst */
  369.     ost[0] = st0;
  370.     sf = *st;
  371.     /* The order for the conversions is significant */
  372.     t = short2blk(st);
  373.     f = short2str(sf);
  374.     xfree((ptr_t) st);
  375. #ifdef VFORK
  376.     Vt = t;
  377. #endif
  378.     (void) execv(f, t);
  379. #ifdef VFORK
  380.     Vt = 0;
  381. #endif
  382.     blkfree((Char **) t);
  383.     /* The sky is falling, the sky is falling! */
  384.  
  385.     case ENOMEM:
  386.     stderror(ERR_SYSTEM, f, strerror(errno));
  387.  
  388. #ifdef _IBMR2
  389.     case 0:            /* execv fails and returns 0! */
  390. #endif                /* _IBMR2 */
  391.     case ENOENT:
  392.     break;
  393.  
  394.     default:
  395.     if (exerr == 0) {
  396.         exerr = strerror(errno);
  397.         if (expath)
  398.         xfree((ptr_t) expath);
  399.         expath = Strsave(sf);
  400. #ifdef VFORK
  401.         Vexpath = expath;
  402. #endif
  403.     }
  404.     }
  405. }
  406.  
  407. /*ARGSUSED*/
  408. void
  409. execash(t, kp)
  410.     Char  **t;
  411.     register struct command *kp;
  412. {
  413.     if (chkstop == 0 && setintr)
  414.     panystop(0);
  415. #ifdef notdef
  416.     /*
  417.      * Why we don't want to close SH* on exec? I think we do... Christos
  418.      */
  419. #ifndef FIOCLEX
  420.     didcch = 1;
  421. #endif
  422. #endif                /* notdef */
  423.     rechist();
  424.     (void) signal(SIGINT, parintr);
  425.     (void) signal(SIGQUIT, parintr);
  426.     (void) signal(SIGTERM, parterm);    /* if doexec loses, screw */
  427.     lshift(kp->t_dcom, 1);
  428.     exiterr = 1;
  429.     doexec(kp);
  430.     /* NOTREACHED */
  431. }
  432.  
  433. void
  434. xechoit(t)
  435.     Char  **t;
  436. {
  437.     if (adrof(STRecho)) {
  438.     flush();
  439.     haderr = 1;
  440.     blkpr(t), xputchar('\n');
  441.     haderr = 0;
  442.     }
  443. }
  444.  
  445. /*ARGSUSED*/
  446. void
  447. dohash(vv, c)
  448.     Char **vv;
  449.     struct command *c;
  450. {
  451. #ifdef COMMENT
  452.     struct stat stb;
  453. #endif
  454.     DIR    *dirp;
  455.     register struct dirent *dp;
  456.     register int cnt;
  457.     int     i = 0;
  458.     struct varent *v = adrof(STRpath);
  459.     Char  **pv;
  460.     int     hashval;
  461. #ifdef __MINT__
  462.     struct varent *suffv = adrof(STRsuffixes);
  463.     Char **suffpv;
  464. #endif
  465.  
  466.     (void) getusername(NULL);    /* flush the tilde cashe */
  467.     tw_clear_comm_list();
  468.     havhash = 1;
  469.     for (cnt = 0; cnt < sizeof xhash; cnt++)
  470.     xhash[cnt] = 0;
  471.     if (v == 0)
  472.     return;
  473.     for (pv = v->vec; *pv; pv++, i++) {
  474. #ifdef __MINT__
  475.     if (!is_abspath(pv[0]))
  476.         continue;
  477. #else
  478.     if (pv[0][0] != '/')
  479.         continue;
  480. #endif
  481.     dirp = opendir(short2str(*pv));
  482.     if (dirp == NULL)
  483.         continue;
  484. #ifdef COMMENT            /* this isn't needed.  opendir won't open
  485.                  * non-dirs */
  486.     if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) {
  487.         (void) closedir(dirp);
  488.         continue;
  489.     }
  490. #endif
  491.     while ((dp = readdir(dirp)) != NULL) {
  492.         if (dp->d_ino == 0)
  493.         continue;
  494.         if (dp->d_name[0] == '.' &&
  495.         (dp->d_name[1] == '\0' ||
  496.          dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
  497.         continue;
  498. #ifdef __MINT__
  499.         {    char *s = rindex(dp->d_name, '.');
  500.  
  501.         if (s && suffv) {
  502.             for (suffpv = suffv->vec; *suffpv; suffpv++) {
  503.             if (!strcmp(s+1, short2str(*suffpv))) {
  504.                 *s = 0; break;
  505.             }
  506.             }
  507.         }
  508.         }
  509. #endif /* __MINT__ */
  510.         hashval = hash(hashname(str2short(dp->d_name)), i);
  511.         bis(xhash, hashval);
  512.         /* tw_add_comm_name (dp->d_name); */
  513.     }
  514.     (void) closedir(dirp);
  515.     }
  516. }
  517.  
  518. /*ARGSUSED*/
  519. void
  520. dounhash(v, c)
  521.     Char **v;
  522.     struct command *c;
  523. {
  524.     havhash = 0;
  525. }
  526.  
  527. #ifdef VFORK
  528. /*ARGSUSED*/
  529. void
  530. hashstat(v, c)
  531.     Char **v;
  532.     struct command *c;
  533. {
  534.     if (hits + misses)
  535.     xprintf("%d hits, %d misses, %d%%\n",
  536.         hits, misses, 100 * hits / (hits + misses));
  537. }
  538.  
  539. #endif
  540.  
  541. /*
  542.  * Hash a command name.
  543.  */
  544. static int
  545. hashname(cp)
  546.     register Char *cp;
  547. {
  548.     register long h = 0;
  549.  
  550.     while (*cp)
  551.     h = hash(h, *cp++);
  552.     return ((int) h);
  553. }
  554.  
  555. int
  556. iscommand(name)
  557.     Char   *name;
  558. {
  559.     register Char **pv;
  560.     register Char *sav;
  561.     register struct varent *v;
  562.     register bool slash = any(short2str(name), '/');
  563.     register int hashval = 0, hashval1, i;
  564.  
  565.     v = adrof(STRpath);
  566.     if (v == 0 || v->vec[0] == 0 || slash)
  567.     pv = justabs;
  568.     else
  569.     pv = v->vec;
  570.     sav = Strspl(STRslash, name);    /* / command name for postpending */
  571.     if (havhash)
  572.     hashval = hashname(name);
  573.     i = 0;
  574.     do {
  575.     if (!slash && pv[0][0] == '/' && havhash) {
  576.         hashval1 = hash(hashval, i);
  577.         if (!bit(xhash, hashval1))
  578.         goto cont;
  579.     }
  580.     if (pv[0][0] == 0 || eq(pv[0], STRdot)) {    /* don't make ./xxx */
  581.         if (executable(NULL, name, 0)) {
  582.         xfree((ptr_t) sav);
  583.         return i + 1;
  584.         }
  585.     }
  586.     else {
  587.         if (executable(*pv, sav, 0)) {
  588.         xfree((ptr_t) sav);
  589.         return i + 1;
  590.         }
  591.     }
  592. cont:
  593.     pv++;
  594.     i++;
  595.     } while (*pv);
  596.     xfree((ptr_t) sav);
  597.     return 0;
  598. }
  599.  
  600. /* Also by:
  601.  *  Andreas Luik <luik@isaak.isa.de>
  602.  *  I S A  GmbH - Informationssysteme fuer computerintegrierte Automatisierung
  603.  *  Azenberstr. 35
  604.  *  D-7000 Stuttgart 1
  605.  *  West-Germany
  606.  * is the executable() routine below and changes to iscommand().
  607.  * Thanks again!!
  608.  */
  609.  
  610. /*
  611.  * executable() examines the pathname obtained by concatenating dir and name
  612.  * (dir may be NULL), and returns 1 either if it is executable by us, or
  613.  * if dir_ok is set and the pathname refers to a directory.
  614.  * This is a bit kludgy, but in the name of optimization...
  615.  */
  616. #ifdef __MINT__
  617. int
  618. executable(dir, name, dir_ok)
  619.     Char   *dir, *name;
  620.     bool    dir_ok;
  621. {
  622.     char *ext, *base;
  623.     int i;
  624.     struct stat stbuf;
  625.     Char    path[MAXPATHLEN + 1];
  626.     char   *strname;
  627.     struct varent *v;
  628.     Char **pv;
  629.  
  630.     if (dir && *dir) {
  631.     copyn(path, dir, MAXPATHLEN);
  632.     catn(path, name, MAXPATHLEN);
  633.     strname = short2str(path);
  634.     }
  635.     else
  636.     strname = short2str(name);
  637.  
  638.     ext = base = alloca(strlen(strname) + 5);
  639.     while (*strname)
  640.     *ext++ = *strname++;
  641.  
  642.     if (stat(base, &stbuf) != -1 &&
  643.         ((dir_ok && S_ISDIR(stbuf.st_mode)) ||
  644.           (S_ISREG(stbuf.st_mode) &&
  645.           ((stbuf.st_mode & (S_IXOTH|S_IXGRP|S_IXUSR))))))
  646.         return 1;
  647.  
  648.     v = adrof(STRsuffixes);
  649.     if (v == 0) return 0;
  650.     
  651.     *ext++ = '.';
  652.     for (pv = v->vec; *pv; pv++) {
  653.     strcpy(ext, short2str(*pv));
  654.     if (stat(base, &stbuf) != -1 &&
  655.         ((dir_ok && S_ISDIR(stbuf.st_mode)) ||
  656.              (S_ISREG(stbuf.st_mode) &&
  657.               ((stbuf.st_mode & (S_IXOTH|S_IXGRP|S_IXUSR)) ||
  658.            !strcmp(ext, "csh")))))
  659.         return 1;
  660.     }
  661.     return 0;
  662. }
  663.  
  664. #else /* __MINT__ */
  665. int
  666. executable(dir, name, dir_ok)
  667.     Char   *dir, *name;
  668.     bool    dir_ok;
  669. {
  670.     struct stat stbuf;
  671.     Char    path[MAXPATHLEN + 1];
  672.     char   *strname;
  673.  
  674.     if (dir && *dir) {
  675.     copyn(path, dir, MAXPATHLEN);
  676.     catn(path, name, MAXPATHLEN);
  677.     strname = short2str(path);
  678.     }
  679.     else
  680.     strname = short2str(name);
  681.     return (stat(strname, &stbuf) != -1 &&
  682.         ((S_ISREG(stbuf.st_mode) &&
  683.     /* save time by not calling access() in the hopeless case */
  684.           (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
  685.           access(strname, X_OK) == 0) ||
  686.          (dir_ok && S_ISDIR(stbuf.st_mode))));
  687. }
  688. #endif /* __MINT__ */
  689.  
  690. void
  691. tellmewhat(lex)
  692.     struct wordent *lex;
  693. {
  694.     register int i;
  695.     register struct biltins *bptr;
  696.     register struct wordent *sp = lex->next;
  697.     bool    aliased = 0;
  698.     Char   *s0, *s1, *s2;
  699.     Char    qc;
  700.  
  701.     if (adrof1(sp->word, &aliases)) {
  702.     alias(lex);
  703.     sp = lex->next;
  704.     aliased = 1;
  705.     }
  706.  
  707.     s0 = sp->word;        /* to get the memory freeing right... */
  708.  
  709.     /* handle quoted alias hack */
  710.     if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
  711.     (sp->word)++;
  712.  
  713.     /* do quoting, if it hasn't been done */
  714.     s1 = s2 = sp->word;
  715.     while (*s2)
  716.     switch (*s2) {
  717.     case '\'':
  718.     case '"':
  719.         qc = *s2++;
  720.         while (*s2 && *s2 != qc)
  721.         *s1++ = *s2++ | QUOTE;
  722.         if (*s2)
  723.         s2++;
  724.         break;
  725.     case '\\':
  726.         if (*++s2)
  727.         *s1++ = *s2++ | QUOTE;
  728.         break;
  729.     default:
  730.         *s1++ = *s2++;
  731.     }
  732.     *s1 = '\0';
  733.  
  734.     for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
  735.     if (eq(sp->word, str2short(bptr->bname))) {
  736.         if (aliased)
  737.         prlex(lex);
  738.         xprintf("%s: shell built-in command.\n", short2str(sp->word));
  739.         flush();
  740.         sp->word = s0;    /* we save and then restore this */
  741.         return;
  742.     }
  743.     }
  744.  
  745.     if (i = iscommand(strip(sp->word))) {
  746.     register Char **pv;
  747.     register struct varent *v;
  748.     bool    slash = any(short2str(sp->word), '/');
  749.  
  750.     v = adrof(STRpath);
  751.     if (v == 0 || v->vec[0] == 0 || slash)
  752.         pv = justabs;
  753.     else
  754.         pv = v->vec;
  755.  
  756.     while (--i)
  757.         pv++;
  758.     if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
  759.         sp->word = Strspl(STRdotsl, sp->word);
  760.         prlex(lex);
  761.         xfree((ptr_t) sp->word);
  762.         sp->word = s0;    /* we save and then restore this */
  763.         return;
  764.     }
  765.     s1 = Strspl(*pv, STRslash);
  766.     sp->word = Strspl(s1, sp->word);
  767.     xfree((ptr_t) s1);
  768.     prlex(lex);
  769.     xfree((ptr_t) sp->word);
  770.     }
  771.     else {
  772.     if (aliased)
  773.         prlex(lex);
  774.     xprintf("%s: Command not found.\n", short2str(sp->word));
  775.     flush();
  776.     }
  777.     sp->word = s0;        /* we save and then restore this */
  778. }
  779.  
  780. #ifdef __MINT__
  781.  
  782. #include <process.h>
  783.  
  784. int
  785. csh_execve(path, argv, envp)
  786.     char *path;
  787.     char **argv, **envp;
  788. {
  789.     int i;
  790.     char *newpath, *s;
  791.     Char **pv;
  792.     struct varent *v;
  793.  
  794.     newpath = s = alloca(strlen(path) + 5);
  795.     while (*path) {
  796.         *s++ = *path++;
  797.     }
  798.     *s = 0;
  799.  
  800.     if (access(newpath, 0) == 0)
  801.         return _spawnve(P_OVERLAY, newpath, argv, envp);
  802.  
  803.     v = adrof(STRsuffixes);
  804.     if (v == 0)
  805.         return -1;
  806.     *s++ = '.';
  807.  
  808.     for (pv = v->vec; *pv; pv++) {
  809.         strcpy(s, short2str(*pv));
  810.         if (access(newpath, 0) == 0) {
  811.             return _spawnve(P_OVERLAY, newpath, argv, envp);
  812.         }
  813.     }
  814.     return -1;
  815. }
  816. #endif /* __MINT__ */
  817.